package bus

import chisel3._
import chisel3.util._
import common.Constants._

object LinkBusCmd {
  // req
  def read           = "b000".U
  def write          = "b001".U
  def probe          = "b100".U

  // resp
  def readLast       = "b010".U
  def writeResp      = "b011".U
  def probeHit       = "b101".U
  def probeMiss      = "b110".U

  def apply() = UInt(3.W)
}

class CoreReqIO(data_width: Int) extends Bundle {
  val addr = Output(UInt(AddrBits.W))
  val wdata = Output(UInt(data_width.W))
  val size = Output(UInt(2.W))// word size
  val cmd = Output(LinkBusCmd())
  override def cloneType = {
    new CoreReqIO(data_width).asInstanceOf[this.type]
  }

  def apply(addr: UInt, wdata: UInt, size: UInt, cmd: UInt) = {
    this.addr := addr
    this.wdata := wdata
    this.size := size
    this.cmd := cmd
    this
  }

  def isRead() = cmd === LinkBusCmd.read || cmd === LinkBusCmd.readLast
  def isWrite() = cmd === LinkBusCmd.write || cmd === LinkBusCmd.writeResp
  def isProbe() = cmd === LinkBusCmd.probe
  def isBurst() = false.B
}

class CoreRespIO(data_width: Int) extends Bundle {
  val cmd = Output(LinkBusCmd())
  val rdata = Output(UInt(data_width.W))

  override def cloneType = {
    new CoreRespIO(data_width).asInstanceOf[this.type]
  }
  def apply(cmd: UInt, data: UInt) = {
    this.rdata := data
    this.cmd := cmd
    this
  }
  def isReadLast() = cmd === LinkBusCmd.readLast
  def isWriteResp() = cmd === LinkBusCmd.writeResp
  def isProbeHit() = cmd === LinkBusCmd.probeHit
  def isProbeMiss() = cmd === LinkBusCmd.probeMiss
}

class CoreLinkIO(data_width: Int) extends Bundle {
  val req = Decoupled(new CoreReqIO(data_width))
  val resp = Flipped(Decoupled(new CoreRespIO(data_width)))

  def apply(valid: Bool, addr: UInt, wdata: UInt, size: UInt, cmd: UInt) = {
    this.req.bits.apply(addr, wdata, size, cmd)
    this.req.valid := valid
    this
  }
  override def cloneType = {
    new CoreLinkIO(data_width).asInstanceOf[this.type]
  }

  // function
  def isRead = req.valid && req.bits.isRead()
  def isWrite = req.valid && req.bits.isWrite()
  def toAXI4Lite() = CoreLinkIOtoAXI4Converter(this, new AXI4Lite, false, 1)
  def toAXI4(isFromCache: Boolean = false, len: Int) = CoreLinkIOtoAXI4Converter(this, new AXI4, isFromCache, len)
}

